/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ambimmort.ucagent.modules.server.dpi;

import cn.net.greenet.db.HibernateUtil;
import cn.net.greenet.db.bean.Dpiendpointbean;
import com.ambimmort.ucagent.appframework.ModuleManager;
import com.ambimmort.ucagent.modules.server.ServerModule;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author 定巍
 */
public class DPIEndPointManager {

    private volatile static DPIEndPointManager instance = null;

    private DPIEndPointManager() {
    }

    public static DPIEndPointManager getInstance() {
        if (instance == null) {
            instance = new DPIEndPointManager();
        }
        return instance;
    }

    private final Map<String, DPIEndPoint> endPoints = new HashMap<String, DPIEndPoint>();

    public synchronized void refresh() {
        Session s = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = s.beginTransaction();
        List list = s.createQuery("FROM Dpiendpointbean").list();
        tx.commit();
        s.close();
        for (Object obj : list) {
            Dpiendpointbean b = (Dpiendpointbean) obj;
            if (!b.isEnabled()) {
                if (endPoints.containsKey(b.getMasterIp())) {
                    DPIEndPoint ep = endPoints.remove(b.getMasterIp());
                    ep.getClientChannel().stop();
                    ep.getServerChannel().disconnect();
                    try {
                        ModuleManager.lookup(ServerModule.class).getWhiteListFilter().disallow(InetAddress.getByName(b.getMasterIp()));
                    } catch (UnknownHostException ex) {
                        Logger.getLogger(DPIEndPointManager.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    try {
                        ModuleManager.lookup(ServerModule.class).getWhiteListFilter().disallow(InetAddress.getByName(b.getMasterIp()));
                    } catch (UnknownHostException ex) {
                        Logger.getLogger(DPIEndPointManager.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            } else {
                if (!endPoints.containsKey(b.getMasterIp())) {
                    endPoints.put(b.getMasterIp(), new DPIEndPoint(b));
                    try {
                        ModuleManager.lookup(ServerModule.class).getWhiteListFilter().allow(InetAddress.getByName(b.getMasterIp()));
                    } catch (UnknownHostException ex) {
                        Logger.getLogger(DPIEndPointManager.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    try {
                        ModuleManager.lookup(ServerModule.class).getWhiteListFilter().allow(InetAddress.getByName(b.getMasterIp()));
                    } catch (UnknownHostException ex) {
                        Logger.getLogger(DPIEndPointManager.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }

        }

        for (DPIEndPoint ep : endPoints.values()) {
            if (!ep.getServerChannel().isConnected()) {
                ep.getDpiEndPointBean().setIsServerChannelConnected(false);
                ep.getDpiEndPointBean().setIsHeartbeatOk(false);
                ep.persistence();
            }
        }

    }

    public synchronized boolean addDPIEndPoint(int id) {
        Session s = HibernateUtil.getSessionFactory().openSession();
        Dpiendpointbean bean = (Dpiendpointbean) s.get(Dpiendpointbean.class, id);
        s.close();
        System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "==>[Function: Enable DPI] DPI: " + bean.getName() + "\t" + bean.getMasterIp());
        if (!this.endPoints.containsKey(bean.getMasterIp())) {
            System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>DPI " + bean.getName() + " Not Found");
            this.endPoints.put(bean.getMasterIp(), new DPIEndPoint(bean));
            System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Add DPI: " + bean.getName() + "");
            try {
                ModuleManager.lookup(ServerModule.class).getWhiteListFilter().allow(InetAddress.getByName(bean.getMasterIp()));
            } catch (UnknownHostException ex) {
                Logger.getLogger(DPIEndPointManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Add DPI Firewall WhiteList: " + bean.getName() + "\t" + bean.getMasterIp());
            System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "==>[Function: Enable DPI] DONE");
            return true;
        } else {
            System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>DPI " + bean.getName() + " already enabled");
            System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "==>[Function: Enable DPI] DONE");
            return false;
        }
    }

    public synchronized boolean removeDPIEndPoint(int id) {
        try {
            Session s = HibernateUtil.getSessionFactory().openSession();
            Dpiendpointbean bean = (Dpiendpointbean) s.get(Dpiendpointbean.class, id);
            s.close();
            System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "==>[Function: Disable DPI] DPI" + bean.getName() + "\t" + bean.getMasterIp());
            if (this.endPoints.containsKey(bean.getMasterIp())) {
                DPIEndPoint ep = this.endPoints.remove(bean.getMasterIp());
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Remove DPI from managed list: " + bean.getName() + "");
                try {
                    ModuleManager.lookup(ServerModule.class).getWhiteListFilter().disallow(InetAddress.getByName(bean.getMasterIp()));
                } catch (UnknownHostException ex) {
                    Logger.getLogger(DPIEndPointManager.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Remove DPI from firewall blacklist: " + bean.getName() + "");
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Stop DPI client channel socket: " + bean.getName() + "\t");
                if (ep.getClientChannel() != null) {
                    ep.getClientChannel().stop();
                }
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Stop DPI client channel socket: stopped");
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Stop DPI server channel socket: " + bean.getName());
                ep.getServerChannel().disconnect();
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>Stop DPI server channel socket: stopped");
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "==>[Function: Disable DPI] DONE");
                return true;
            } else {
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "=>DPI " + bean.getName() + " Not Found");
                System.out.println("[Thread:" + Thread.currentThread().getId() + "]" + "==>[Function: Disable DPI] DONE");
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    public DPIEndPoint getByName(String devName) {
        for (DPIEndPoint dpi : endPoints.values()) {
            if (dpi.getDpiEndPointBean().getName().equals(devName)) {
                return dpi;
            }
        }
        return null;
    }

    public Map<String, DPIEndPoint> getEndPoints() {
        return endPoints;
    }

}
